// filepath: /home/debi/IdeaProjects/LearnRust/Work/basic/src/stdx/f64x/f64x.rs
// `Work/basic/src/stdx/f64x/f64x.rs`
// f64 常见方法示例：sqrt, powf, powi, to_bits, from_bits, 分类方法，取整/舍入等。
// 所有示例带中文注释，便于学习与测试。

use std::f32::consts::PI;

/// 简要示例函数：展示如何调用部分 f64 方法（供手动调用）
///
/// 输入：无
/// 输出：无（仅在调试时打印），演示用
#[allow(dead_code)]
pub fn stdx_examples_f64x() {
    // 说明：下面示例并不覆盖所有方法，只挑选常见且容易混淆的用法
    let a: f64 = 1.0 / 3.0;
    // is_nan: 用于检测 NaN（不是普通的比较）
    let is_nan = a.is_nan(); // false
    // is_finite: 检查是否是有限数
    let is_finite = a.is_finite(); // true
    // 打印示例：便于观察
    println!(
        "示例 a = {}, is_nan = {}, is_finite = {}",
        a, is_nan, is_finite
    );
}

// ---------------- 常量与三角函数示例 ----------------
/// 常量与三角函数示例
///
/// 说明：演示数学常量（PI）、机器相关常量（EPSILON、MAX 等）与三角函数的基本用法及一个近似恒等式
#[test]
fn f64_consts_and_trig() {
    // 平台与数学常量
    println!("PI = {}", PI); // PI 常量
    println!("EPSILON = {}", f64::EPSILON); // 表示相对精度的下界
    println!(
        "MAX = {} MIN = {} MIN_POSITIVE = {}",
        f64::MAX,
        f64::MIN,
        f64::MIN_POSITIVE
    );
    // 三角函数与恒等式近似示例
    let angle = PI / 6.0; // 30 度
    // sin / cos 的返回值范围为 [-1, 1]
    let s = angle.sin();
    let c = angle.cos();
    // sin^2 + cos^2 理论值为 1，浮点计算存在舍入误差，用近似比较
    assert!((s.powi(2) + c.powi(2) - 1.0).abs() < 1e-12);
}

// ---------------- 幂、开方与 fused mul_add ----------------
/// 幂、开方与 fused mul_add 示例
///
/// 说明：展示 powf、powi、sqrt，以及 mul_add（可能为硬件 fused 操作）
#[test]
fn f64_pow_sqrt_mul_add() {
    let x = 9.0f64;
    // sqrt/powf/powi 用法示例
    assert_eq!(x.sqrt(), 3.0);
    assert_eq!(x.powf(0.5), 3.0);
    assert_eq!(2.0f64.powi(10), 1024.0);

    // mul_add: 以合并乘加的方式计算 m * n + t
    // 当硬件支持 fused multiply-add 时，这个调用可以减少中间舍入损失
    let m = 1.5f64;
    let n = 2.0f64;
    let t = 3.0f64;
    let normal = m * n + t; // 可能存在两次舍入
    let fused = m.mul_add(n, t); // 可能只产生一次舍入（更精确）
    // 近似比较结果（两者可能相等也可能略有差别）
    assert!((fused - normal).abs() < 1e-12);
}

// ---------------- 取整、截断与舍入 ----------------
/// 取整、截断与舍入行为示例
///
/// 说明：展示 floor/ceil/trunc/fract/round 的行为，特别说明 round 的银行家舍入策略
#[test]
fn f64_rounding_truncation() {
    let v = 3.7f64;
    assert_eq!(v.floor(), 3.0); // 向下取整
    assert_eq!(v.ceil(), 4.0); // 向上取整
    assert_eq!(v.trunc(), 3.0); // 截断小数部分，保留整数部分（朝 0）
    // 小数部分（注意浮点可能存在微小误差，使用近似比较）
    assert!(
        (v.fract() - 0.7).abs() < 1e-12,
        "fract 值与 0.7 存在可接受的微小误差"
    );

    // round: 银行家舍入（.5 向最近的偶数）
    // 2.5 -> 2.0 因为 2 为最近的偶数；3.5 -> 4.0
    assert_eq!(2.5f64.round(), 2.0);
    assert_eq!(3.5f64.round(), 4.0);

    // 注意：负数的 round/floor/ceil/trunc 行为应分别验证
    let neg = -2.5f64;
    // -2.5 round -> -2.0（因为 -2 为偶数）
    assert_eq!(neg.round(), -2.0);
}

// ---------------- 浮点数分类与次正规数 ----------------
/// 浮点数分类示例（NaN, infinite, finite, normal）
///
/// 说明：演示如何通过 is_nan/is_infinite/is_finite/is_normal 来判断数的类别，并展示次正规数情况
#[test]
fn f64_classification_examples() {
    let nan = f64::NAN;
    let inf = f64::INFINITY;
    let neg_inf = f64::NEG_INFINITY;
    let normal = 1.23f64;
    let subnormal = f64::MIN_POSITIVE / 2.0; // 小于最小正正规数的值，属于次正规数

    assert!(nan.is_nan()); // NaN 检测
    assert!(inf.is_infinite()); // 正无穷
    assert!(neg_inf.is_infinite()); // 负无穷
    assert!(normal.is_finite() && normal.is_normal()); // 正常数（非次正规）

    // 次正规数通常 is_normal() 返回 false
    println!(
        "subnormal = {}, is_normal = {}",
        subnormal,
        subnormal.is_normal()
    );
}

// ---------------- 位级操作（to_bits / from_bits）与 NaN 构造 ----------------
/// 位级操作示例：to_bits / from_bits，并演示如何构造 NaN
///
/// 说明：to_bits 返回 IEEE-754 二进制表示（u64），from_bits 可根据位模式还原浮点数。
/// 通过位级构造可以生成特定类型的 NaN 或检查符号位、指数、尾数等。
#[test]
fn f64_bits_examples() {
    let x = 2.5f64;
    // 将浮点数转换为位表示（u64），便于分析其底层 IEEE-754 编码
    let bits = x.to_bits();
    // 再从位表示构造回浮点数，应与原值相同
    let y = f64::from_bits(bits);
    assert_eq!(x, y);

    // 构造一个 quiet NaN（示例位模式，具体位模式仅作教学用途）
    // 注意：不同平台/实现可能对 NaN 位模式有额外约束，但 IEEE-754 定义了 NaN 的基本结构
    let qnan_bits: u64 = 0x7FF8_0000_0000_0001;
    let qnan = f64::from_bits(qnan_bits);
    assert!(qnan.is_nan());

    // 不要用 == 去比较 NaN（任何与 NaN 的比较都是 false）
    let nan1 = f64::NAN;
    assert!(!(nan1 == nan1));

    // 示例：检查符号位（最高位），以及指数是否全 1（可能表示无穷或 NaN）
    let sign_bit = (bits >> 63) & 1; // 取最高位
    let exponent = (bits >> 52) & 0x7FF; // 指数部分（11 位）
    let mantissa = bits & 0xFFFFFFFFFFFFF; // 尾数部分（52 位）
    println!(
        "bits sign={}, exp=0x{:03X}, mantissa=0x{:013X}",
        sign_bit, exponent, mantissa
    );
}

// ---------------- NaN 比较与近似比较 ----------------
/// 与 NaN 比较与排序注意事项
///
/// 说明：NaN 与任何值比较（<, >, ==）都返回 false，使用 is_nan 检测；数值近似比较使用绝对差
#[test]
fn f64_nan_comparison_behavior() {
    let a = 1.0f64;
    let nan = f64::NAN;
    // 任何与 NaN 的常规比较都不是 true，因此应使用 is_nan 来判断
    assert!(!(a < nan));
    assert!(!(a > nan));
    assert!(!(a == nan));
    assert!(nan.is_nan());

    // 浮点数比较要注意舍入误差，通常使用绝对差或相对误差
    let p = 0.1f64 + 0.2f64; // 这两项相加会产生舍入误差
    let q = 0.3f64;
    // 直接比较可能为 false，所以用 abs 差值小于容忍度来判定近似相等
    assert!((p - q).abs() < 1e-15);
}

// ---------------- 符号位与无穷检查 ----------------
/// 符号位与无穷检查示例
///
/// 说明：通过 to_bits 可读取符号位，也可以直接使用 is_infinite/is_sign_positive/is_sign_negative
#[test]
fn f64_sign_and_infinite_check() {
    let neg = -3.5f64;
    // 获取符号位：最高位为 1 表示负数
    let sign_bit = neg.to_bits() >> 63;
    assert_eq!(sign_bit, 1);

    // 也可以直接检查符号方法
    assert!(neg.is_sign_negative());

    // 无穷检测
    assert!(f64::INFINITY.is_infinite());
    assert!(f64::NEG_INFINITY.is_infinite());
}
